﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Interop;
using System.Windows.Media;
using Black.SurfaceToolkit.Tools;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;
using Core = Microsoft.Surface.Core;

namespace Black.SurfaceToolkit.Controls
{
    /// <summary>
    /// <see cref="T:Microsoft.Surface.Presentation.Controls.ScatterView" /> simplifié et plus stable.
    /// </summary>
    /// <remarks>
    /// <para>Ce contrôle permet de manipuler des éléments pour en changer leur taille (<see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.Scale" />), orientation (<see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.Orientation" />) ou position (<see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.Center" />).</para>
    /// <para>Les manipulations sont activables via <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.CanMove" />, <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.CanRotate" /> ou <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.CanScale" />.</para>
    /// <para>Les conteneurs enfants peuvent avoir chacun un niveau de calque (<see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.LevelOfView" />) permettant ainsi de générer automatiquement leur <see cref="P:System.Windows.Controls.Panel.ZIndex" /> avec priorités et sans conflis. Un conteneur ne sera jamais au dessus d'un conteneur dont le niveau est supérieur.</para>
    /// <para><see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.FlingOutMode" /> permet d'indiquer sur quels bords du contrôle les éléments enfants peuvent être sortis (par jet).</para>
    /// <para><div class="caption" style="font-weight : bold">CanvasScatterView avec 3 éléments</div></para>
    /// <para><img src="../Images/CanvasScatterView.Normal.png" /></para>
    /// <para>Ce composant est une alternative au <see cref="T:Microsoft.Surface.Presentation.Controls.ScatterView" />.</para>
    /// </remarks>
    [TemplatePart(Name = CanvasScatterView.CANVAS_ITEMS_NAME, Type = typeof(Canvas))]
    [TemplatePart(Name = CanvasScatterView.CANVAS_MAIN_NAME, Type = typeof(Canvas))]
    [Browsable(true), Description("CanvasScatterView pour Surface")]
    public class CanvasScatterView : SurfaceItemsControl
    {
        #region Constantes

        /// <summary>
        /// Nom du <see cref="T:System.Windows.Controls.Canvas" /> des éléments.
        /// </summary>
        protected const string CANVAS_ITEMS_NAME = "PART_canItems";

        /// <summary>
        /// Nom du <see cref="T:System.Windows.Controls.Canvas" /> principal.
        /// </summary>
        protected const string CANVAS_MAIN_NAME = "PART_canMain";

        #endregion

        #region Propriétés de dépendance

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.AngularDecelerationRate" />.
        /// </summary>
        public static readonly DependencyProperty AngularDecelerationRateProperty = DependencyProperty.Register("AngularDecelerationRate", typeof(double), typeof(CanvasScatterView), new UIPropertyMetadata(0.0000001));
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.CanMove" />.
        /// </summary>
        public static readonly DependencyProperty CanMoveProperty = DependencyProperty.Register("CanMove", typeof(bool), typeof(CanvasScatterView), new UIPropertyMetadata(BooleanBoxes.TrueBox));
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.CanRotate" />.
        /// </summary>
        public static readonly DependencyProperty CanRotateProperty = DependencyProperty.Register("CanRotate", typeof(bool), typeof(CanvasScatterView), new UIPropertyMetadata(BooleanBoxes.TrueBox));
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.CanScale" />.
        /// </summary>
        public static readonly DependencyProperty CanScaleProperty = DependencyProperty.Register("CanScale", typeof(bool), typeof(CanvasScatterView), new UIPropertyMetadata(BooleanBoxes.TrueBox));
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.DecelerationRate" />.
        /// </summary>
        public static readonly DependencyProperty DecelerationRateProperty = DependencyProperty.Register("DecelerationRate", typeof(double), typeof(CanvasScatterView), new UIPropertyMetadata(0.001));
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.ExpansionDecelerationRate" />.
        /// </summary>
        public static readonly DependencyProperty ExpansionDecelerationRateProperty = DependencyProperty.Register("ExpansionDecelerationRate", typeof(double), typeof(CanvasScatterView), new UIPropertyMetadata(0.0001));
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.FlingOutMode" />.
        /// </summary>
        public static readonly DependencyProperty FlingOutModeProperty = DependencyProperty.Register("FlingOutMode", typeof(FlingOutMode), typeof(CanvasScatterView), new FrameworkPropertyMetadata(FlingOutMode.All, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.AffectsRender));
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.IsFlingOutEnabled" />.
        /// </summary>
        public static readonly DependencyProperty IsFlingOutEnabledProperty = DependencyProperty.Register("IsFlingOutEnabled", typeof(bool), typeof(CanvasScatterView), new UIPropertyMetadata(BooleanBoxes.TrueBox));
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.IsInertiaEnabled" />.
        /// </summary>
        public static readonly DependencyProperty IsInertiaEnabledProperty = DependencyProperty.Register("IsInertiaEnabled", typeof(bool), typeof(CanvasScatterView), new UIPropertyMetadata(BooleanBoxes.TrueBox));
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.LevelOfView" />.
        /// </summary>
        public static readonly DependencyProperty LevelOfViewProperty = DependencyProperty.RegisterAttached("LevelOfView", typeof(int), typeof(CanvasScatterView), new UIPropertyMetadata(0, new PropertyChangedCallback(CanvasScatterView.OnLevelOfViewChanged)));
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.Selection" />.
        /// </summary>
        public static readonly DependencyProperty SelectionProperty = DependencyProperty.Register("Selection", typeof(object), typeof(CanvasScatterView), new UIPropertyMetadata(null, new PropertyChangedCallback(CanvasScatterView.OnSelectionChanged)));
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.SizeTransform" />.
        /// </summary>
        public static readonly DependencyProperty SizeTransformProperty = DependencyProperty.Register("SizeTransform", typeof(SizeTransformMode), typeof(CanvasScatterView), new UIPropertyMetadata(SizeTransformMode.Continue));

        #endregion

        #region Evénements routés

        /// <summary>
        /// Identifie l'événement routé <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterView.AllOperationCompleted" />.
        /// </summary>
        public static readonly RoutedEvent AllOperationCompletedEvent = EventManager.RegisterRoutedEvent("AllOperationCompleted", RoutingStrategy.Bubble, typeof(OperationCompletedRoutedEventHandler), typeof(CanvasScatterView));
        /// <summary>
        /// Identifie l'événement routé <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterView.AllOperationDelta" />.
        /// </summary>
        public static readonly RoutedEvent AllOperationDeltaEvent = EventManager.RegisterRoutedEvent("AllOperationDelta", RoutingStrategy.Bubble, typeof(OperationDeltaRoutedEventHandler), typeof(CanvasScatterView));
        /// <summary>
        /// Identifie l'événement routé <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterView.AllOperationStarted" />.
        /// </summary>
        public static readonly RoutedEvent AllOperationStartedEvent = EventManager.RegisterRoutedEvent("AllOperationStarted", RoutingStrategy.Bubble, typeof(OperationStartedRoutedEventHandler), typeof(CanvasScatterView));
        /// <summary>
        /// Identifie l'événement routé <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterView.CanvasDragEnded" />.
        /// </summary>
        public static readonly RoutedEvent CanvasDragEndedEvent = EventManager.RegisterRoutedEvent("CanvasDragEnded", RoutingStrategy.Bubble, typeof(DragItemRoutedEventHandler), typeof(CanvasScatterView));
        /// <summary>
        /// Identifie l'événement routé <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterView.CanvasDragStarted" />.
        /// </summary>
        public static readonly RoutedEvent CanvasDragStartedEvent = EventManager.RegisterRoutedEvent("CanvasDragStarted", RoutingStrategy.Bubble, typeof(DragItemRoutedEventHandler), typeof(CanvasScatterView));
        /// <summary>
        /// Identifie l'événement routé <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterView.CanvasFlingOutCompleted" />.
        /// </summary>
        public static readonly RoutedEvent CanvasFlingOutCompletedEvent = EventManager.RegisterRoutedEvent("CanvasFlingOutCompleted", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(CanvasScatterView));
        /// <summary>
        /// Identifie l'événement routé <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterView.InertiaCompleted" />.
        /// </summary>
        public static readonly RoutedEvent InertiaCompletedEvent = EventManager.RegisterRoutedEvent("InertiaCompleted", RoutingStrategy.Bubble, typeof(OperationCompletedRoutedEventHandler), typeof(CanvasScatterView));
        /// <summary>
        /// Identifie l'événement routé <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterView.InertiaDelta" />.
        /// </summary>
        public static readonly RoutedEvent InertiaDeltaEvent = EventManager.RegisterRoutedEvent("InertiaDelta", RoutingStrategy.Bubble, typeof(OperationDeltaRoutedEventHandler), typeof(CanvasScatterView));
        /// <summary>
        /// Identifie l'événement routé <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterView.InertiaStarted" />.
        /// </summary>
        public static readonly RoutedEvent InertiaStartedEvent = EventManager.RegisterRoutedEvent("InertiaStarted", RoutingStrategy.Bubble, typeof(OperationStartedRoutedEventHandler), typeof(CanvasScatterView));
        /// <summary>
        /// Identifie l'événement routé <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterView.ManipulationCompleted" />.
        /// </summary>
        public static readonly RoutedEvent ManipulationCompletedEvent = EventManager.RegisterRoutedEvent("ManipulationCompleted", RoutingStrategy.Bubble, typeof(OperationCompletedRoutedEventHandler), typeof(CanvasScatterView));
        /// <summary>
        /// Identifie l'événement routé <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterView.ManipulationDelta" />.
        /// </summary>
        public static readonly RoutedEvent ManipulationDeltaEvent = EventManager.RegisterRoutedEvent("ManipulationDelta", RoutingStrategy.Bubble, typeof(OperationDeltaRoutedEventHandler), typeof(CanvasScatterView));
        /// <summary>
        /// Identifie l'événement routé <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterView.ManipulationStarted" />.
        /// </summary>
        public static readonly RoutedEvent ManipulationStartedEvent = EventManager.RegisterRoutedEvent("ManipulationStarted", RoutingStrategy.Bubble, typeof(OperationStartedRoutedEventHandler), typeof(CanvasScatterView));
        /// <summary>
        /// Identifie l'événement routé <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterView.SelectionChanged" />.
        /// </summary>
        public static readonly RoutedEvent SelectionChangedEvent = EventManager.RegisterRoutedEvent("SelectionChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(CanvasScatterView));

        #endregion

        #region Evénéments

        /// <summary>
        /// Se produit lorsque tous les processeurs ont terminés leurs interventions.
        /// </summary>
        public event OperationCompletedRoutedEventHandler AllOperationCompleted
        {
            add
            {
                this.AddHandler(CanvasScatterView.AllOperationCompletedEvent, value);
            }
            remove
            {
                this.RemoveHandler(CanvasScatterView.AllOperationCompletedEvent, value);
            }
        }

        /// <summary>
        /// Se produit lorsque l'un des processeurs produit une modification.
        /// </summary>
        public event OperationDeltaRoutedEventHandler AllOperationDelta
        {
            add
            {
                this.AddHandler(CanvasScatterView.AllOperationDeltaEvent, value);
            }
            remove
            {
                this.RemoveHandler(CanvasScatterView.AllOperationDeltaEvent, value);
            }
        }

        /// <summary>
        /// Se produit lorsque l'un des processeurs démarre.
        /// </summary>
        public event OperationStartedRoutedEventHandler AllOperationStarted
        {
            add
            {
                this.AddHandler(CanvasScatterView.AllOperationStartedEvent, value);
            }
            remove
            {
                this.RemoveHandler(CanvasScatterView.AllOperationStartedEvent, value);
            }
        }

        /// <summary>
        /// Se produit lorsqu'un glissement se termine.
        /// </summary>
        public event DragItemRoutedEventHandler CanvasDragEnded
        {
            add
            {
                this.AddHandler(CanvasScatterView.CanvasDragEndedEvent, value);
            }
            remove
            {
                this.RemoveHandler(CanvasScatterView.CanvasDragEndedEvent, value);
            }
        }

        /// <summary>
        /// Se produit lorsqu'un glissement démarre.
        /// </summary>
        public event DragItemRoutedEventHandler CanvasDragStarted
        {
            add
            {
                this.AddHandler(CanvasScatterView.CanvasDragStartedEvent, value);
            }
            remove
            {
                this.RemoveHandler(CanvasScatterView.CanvasDragStartedEvent, value);
            }
        }

        /// <summary>
        /// Se produit lorsqu'un lorsqu'un Fling Out se termine.
        /// </summary>
        public event RoutedEventHandler CanvasFlingOutCompleted
        {
            add
            {
                this.AddHandler(CanvasScatterView.CanvasFlingOutCompletedEvent, value);
            }
            remove
            {
                this.RemoveHandler(CanvasScatterView.CanvasFlingOutCompletedEvent, value);
            }
        }

        /// <summary>
        /// Se produit lorsque le processeur d'inertie a terminé son intervention.
        /// </summary>
        public event OperationCompletedRoutedEventHandler InertiaCompleted
        {
            add
            {
                this.AddHandler(CanvasScatterView.InertiaCompletedEvent, value);
            }
            remove
            {
                this.RemoveHandler(CanvasScatterView.InertiaCompletedEvent, value);
            }
        }

        /// <summary>
        /// Se produit lorsque le processeur d'inertie produit une modification.
        /// </summary>
        public event OperationDeltaRoutedEventHandler InertiaDelta
        {
            add
            {
                this.AddHandler(CanvasScatterView.InertiaDeltaEvent, value);
            }
            remove
            {
                this.RemoveHandler(CanvasScatterView.InertiaDeltaEvent, value);
            }
        }

        /// <summary>
        /// Se produit lorsque le processeur d'inertie démarre.
        /// </summary>
        public event OperationStartedRoutedEventHandler InertiaStarted
        {
            add
            {
                this.AddHandler(CanvasScatterView.InertiaStartedEvent, value);
            }
            remove
            {
                this.RemoveHandler(CanvasScatterView.InertiaStartedEvent, value);
            }
        }

        /// <summary>
        /// Se produit lorsque le processeur de manipulation a terminé son intervention.
        /// </summary>
        public event OperationCompletedRoutedEventHandler ManipulationCompleted
        {
            add
            {
                this.AddHandler(CanvasScatterView.ManipulationCompletedEvent, value);
            }
            remove
            {
                this.RemoveHandler(CanvasScatterView.ManipulationCompletedEvent, value);
            }
        }

        /// <summary>
        /// Se produit lorsque le processeur de manipulation produit une modification.
        /// </summary>
        public event OperationDeltaRoutedEventHandler ManipulationDelta
        {
            add
            {
                this.AddHandler(CanvasScatterView.ManipulationDeltaEvent, value);
            }
            remove
            {
                this.RemoveHandler(CanvasScatterView.ManipulationDeltaEvent, value);
            }
        }

        /// <summary>
        /// Se produit lorsque le processeur de manipulation démarre.
        /// </summary>
        public event OperationStartedRoutedEventHandler ManipulationStarted
        {
            add
            {
                this.AddHandler(CanvasScatterView.ManipulationStartedEvent, value);
            }
            remove
            {
                this.RemoveHandler(CanvasScatterView.ManipulationStartedEvent, value);
            }
        }

        /// <summary>
        /// Se produit lorsque l'élément séléctionné change.
        /// </summary>
        public event RoutedEventHandler SelectionChanged
        {
            add
            {
                this.AddHandler(CanvasScatterView.SelectionChangedEvent, value);
            }
            remove
            {
                this.RemoveHandler(CanvasScatterView.SelectionChangedEvent, value);
            }
        }

        #endregion

        #region Accesseurs

        /// <summary>
        /// Obtient ou définit la décélération angulaire pour l'inertie.
        /// </summary>
        [Browsable(true), DefaultValue(0.0000001), Description("Décélération angulaire pour l'inertie"), Category("CanvasScatterView")]
        public double AngularDecelerationRate
        {
            get
            {
                return ((double)this.GetValue(CanvasScatterView.AngularDecelerationRateProperty));
            }
            set
            {
                this.SetValue(CanvasScatterView.AngularDecelerationRateProperty, value);
            }
        }

        /// <summary>
        /// Obtient ou définit une valeur indiquant si l'élément peut être déplacé.
        /// </summary>
        [Browsable(true), DefaultValue(true), Description("Valeur indiquant si l'élément peut être déplacé"), Category("CanvasScatterView")]
        public bool CanMove
        {
            get
            {
                return ((bool)this.GetValue(CanvasScatterView.CanMoveProperty));
            }
            set
            {
                this.SetValue(CanvasScatterView.CanMoveProperty, BooleanBoxes.Box(value));
            }
        }

        /// <summary>
        /// Obtient ou définit une valeur indiquant si l'élément peut être tourné.
        /// </summary>
        [Browsable(true), DefaultValue(true), Description("Valeur indiquant si l'élément peut être tourné"), Category("CanvasScatterView")]
        public bool CanRotate
        {
            get
            {
                return ((bool)this.GetValue(CanvasScatterView.CanRotateProperty));
            }
            set
            {
                this.SetValue(CanvasScatterView.CanRotateProperty, BooleanBoxes.Box(value));
            }
        }

        /// <summary>
        /// Obtient ou définit une valeur indiquant si l'élément peut être redimensionné.
        /// </summary>
        [Browsable(true), DefaultValue(true), Description("Valeur indiquant si l'élément peut être redimensionné"), Category("CanvasScatterView")]
        public bool CanScale
        {
            get
            {
                return ((bool)this.GetValue(CanvasScatterView.CanScaleProperty));
            }
            set
            {
                this.SetValue(CanvasScatterView.CanScaleProperty, BooleanBoxes.Box(value));
            }
        }

        /// <summary>
        /// Obtient ou définit le coéficient de décélération de l'intertie.
        /// </summary>
        [Browsable(true), DefaultValue(0.001) , Description("Coéficient de décélération de l'intertie"), Category("CanvasScatterView")]
        public double DecelerationRate
        {
            get
            {
                return ((double)this.GetValue(CanvasScatterView.DecelerationRateProperty));
            }
            set
            {
                this.SetValue(CanvasScatterView.DecelerationRateProperty, value);
            }
        }

        /// <summary>
        /// Obtient ou définit le coéficient d'expansion de la décélération de l'intertie.
        /// </summary>
        [Browsable(true), DefaultValue(0.0001), Description("Coéficient d'expansion de la décélération de l'intertie"), Category("CanvasScatterView")]
        public double ExpansionDecelerationRate
        {
            get
            {
                return ((double)this.GetValue(CanvasScatterView.ExpansionDecelerationRateProperty));
            }
            set
            {
                this.SetValue(CanvasScatterView.ExpansionDecelerationRateProperty, value);
            }
        }

        /// <summary>
        /// Obtient ou définit le mode du Fling Out
        /// </summary>
        [Browsable(true), DefaultValue(FlingOutMode.All), Description("Mode du fling out"), Category("CanvasScatterView")]
        public FlingOutMode FlingOutMode
        {
            get
            {
                return ((FlingOutMode)this.GetValue(CanvasScatterView.FlingOutModeProperty));
            }
            set
            {
                this.SetValue(CanvasScatterView.FlingOutModeProperty, value);
            }
        }

        /// <summary>
        /// Obtient ou définit si le Fling Out sur les éléments est actif.
        /// </summary>
        [Browsable(true), DefaultValue(true), Description("Valeur indiquant si le Fling Out sur les éléments est acivé"), Category("CanvasScatterView")]
        public bool IsFlingOutEnabled
        {
            get
            {
                return ((bool)this.GetValue(CanvasScatterView.IsFlingOutEnabledProperty));
            }
            set
            {
                this.SetValue(CanvasScatterView.IsFlingOutEnabledProperty, BooleanBoxes.Box(value));
            }
        }

        /// <summary>
        /// Obtient ou définit si l'inertie est activée.
        /// </summary>
        [Browsable(true), DefaultValue(true), Description("Valeur indiquant si l'inertie est activée"), Category("CanvasScatterView")]
        public bool IsInertiaEnabled
        {
            get
            {
                return ((bool)this.GetValue(CanvasScatterView.IsInertiaEnabledProperty));
            }
            set
            {
                this.SetValue(CanvasScatterView.IsInertiaEnabledProperty, BooleanBoxes.Box(value));
            }
        }

        /// <summary>
        /// Obtient l'objet en cours de sélection.
        /// </summary>
        [Browsable(false)]
        public object Selection
        {
            get
            {
                return ((object)this.GetValue(CanvasScatterView.SelectionProperty));
            }
            internal set
            {
                this.SetValue(CanvasScatterView.SelectionProperty, value);
            }
        }

        /// <summary>
        /// Obtient ou définit le mode de redimensionnement du contrôle
        /// </summary>
        [Browsable(true), DefaultValue(SizeTransformMode.Continue), Description("Mode de redimensionnement du contrôle"), Category("CanvasScatterView")]
        public SizeTransformMode SizeTransform
        {
            get
            {
                return ((SizeTransformMode)this.GetValue(CanvasScatterView.SizeTransformProperty));
            }
            set
            {
                this.SetValue(CanvasScatterView.SizeTransformProperty, value);
            }
        }

        #endregion

        #region Variables d'instance

        private Core.ContactTarget m_oContactTarget;
        private Canvas m_oRefItems;
        private Canvas m_oRefRoot;

        #endregion

        #region Constructeurs

        /// <summary>
        /// Initialise la classe <see cref="T:Black.SurfaceToolkit.Controls.CanvasScatterView" />.
        /// </summary>
        static CanvasScatterView()
        {
            FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(CanvasScatterView), new FrameworkPropertyMetadata(typeof(CanvasScatterView)));
        }

        /// <summary>
        /// Initialise une nouvelle instance de <see cref="T:Black.SurfaceToolkit.Controls.CanvasScatterView" />.
        /// </summary>
        public CanvasScatterView()
            : base()
        {
        }

        #endregion

        #region Fonctions publiques

        /// <summary>
        /// Applique un agrandissement à tous les éléments ouverts.
        /// </summary>
        /// <param name="p_dScale">Agrandissement à appliquer à tous les éléments ouverts.</param>
        public void ApplyScaleToAll(double p_dScale)
        {
            foreach (object oItem in this.Items)
            {
                CanvasScatterViewItem oContainer = this.ItemContainerGenerator.ContainerFromItem(oItem) as CanvasScatterViewItem;

                if (oContainer != null)
                    oContainer.Scale = p_dScale;
            }
        }

        /// <summary>
        /// Appelée pour appliquer le template.
        /// </summary>
        public override void OnApplyTemplate()
        {
            // Traitement parent

            base.OnApplyTemplate();

            // Récupération des containers

            this.m_oRefRoot = (Canvas)this.Template.FindName(CanvasScatterView.CANVAS_MAIN_NAME, this);
            this.m_oRefItems = (Canvas)this.Template.FindName(CanvasScatterView.CANVAS_ITEMS_NAME, this);

            // Création du scrutateur

            Window oSource = this.FindWindow();

            if (oSource != null)
            {
                this.m_oContactTarget = new Core.ContactTarget(new WindowInteropHelper(oSource).Handle, Core.EventThreadChoice.OnBackgroundThread);
                this.m_oContactTarget.EnableInput();
            }
        }

        /// <summary>
        /// Démarre un glisser-déposer.
        /// </summary>
        /// <param name="p_oContact">Contact source du glisser-déposer</param>
        /// <param name="p_oIcon">Image à afficher.</param>
        public void StartDragDrop(Contact p_oContact, ImageSource p_oIcon)
        {
            this.StartDragDrop(p_oContact, p_oIcon, null, p_oIcon.Width, p_oIcon.Height);
        }

        /// <summary>
        /// Démarre un glisser-déposer.
        /// </summary>
        /// <param name="p_oContact">Contact source du glisser-déposer</param>
        /// <param name="p_oIcon">Image à afficher.</param>
        /// <param name="p_dDragWidth">Largeur du contrôle.</param>
        /// <param name="p_dDragHeight">Hauteur du contrôle.</param>
        public void StartDragDrop(Contact p_oContact, ImageSource p_oIcon, double p_dDragWidth, double p_dDragHeight)
        {
            this.StartDragDrop(p_oContact, p_oIcon, null, p_dDragWidth, p_dDragHeight);
        }

        /// <summary>
        /// Démarre un glisser-déposer.
        /// </summary>
        /// <param name="p_oContact">Contact source du glisser-déposer</param>
        /// <param name="p_oIcon">Image à afficher.</param>
        /// <param name="p_oData">Informations du glisser-déposer.</param>
        public void StartDragDrop(Contact p_oContact, ImageSource p_oIcon, object p_oData)
        {
            this.StartDragDrop(p_oContact, p_oIcon, p_oData, p_oIcon.Width, p_oIcon.Height);
        }

        /// <summary>
        /// Démarre un glisser-déposer.
        /// </summary>
        /// <param name="p_oContact">Contact source du glisser-déposer</param>
        /// <param name="p_oIcon">Image à afficher.</param>
        /// <param name="p_oData">Informations du glisser-déposer.</param>
        /// <param name="p_dDragWidth">Largeur du contrôle.</param>
        /// <param name="p_dDragHeight">Hauteur du contrôle.</param>
        public void StartDragDrop(Contact p_oContact, ImageSource p_oIcon, object p_oData, double p_dDragWidth, double p_dDragHeight)
        {
            // Vérification existance contact

            if (p_oContact == null || !this.IsContactAlive(p_oContact.Id))
                return;

            // Création de l'élément

            CanvasScatterViewDragItem oItem = new CanvasScatterViewDragItem(this.m_oRefRoot, p_oData, p_oContact, p_oIcon, p_dDragWidth, p_dDragHeight);

            // On se bind sur le drop

            oItem.ItemDragEnded += new DragItemRoutedEventHandler(this.Item_ItemDragEnded);

            // On capture le contact

            Contacts.CaptureContact(p_oContact, oItem);

            // On lance l'event

            this.RaiseCanvasDragStartedEvent(p_oData, p_oContact.GetPosition(this.m_oRefRoot), p_oContact.Id);
        }

        #endregion

        #region Fonctions internes

        /// <summary>
        /// Redéfinit les <see cref="P:System.Windows.Controls.Panel.ZIndex" /> des conteneurs de la liste.
        /// </summary>
        /// <param name="p_oOnTop">Conteneur à mettre en avant dans son calque.</param>
        internal void RefreshZIndexes(object p_oOnTop)
        {
            UIElement oOnTopContainer = (this.ItemContainerGenerator.ContainerFromItem(p_oOnTop) ?? p_oOnTop as DependencyObject) as UIElement;
            int iOnTopLevelOfView = oOnTopContainer == null ? 0 : CanvasScatterView.GetLevelOfView(oOnTopContainer);

            IOrderedEnumerable<IGrouping<int, DependencyObject>> oItemsGroup = (from oItem in this.Items.OfType<object>()
                                                                                let oContainer = this.ItemContainerGenerator.ContainerFromItem(oItem) ?? oItem as DependencyObject
                                                                                let iLevelOfView = CanvasScatterView.GetLevelOfView(oContainer)
                                                                                group oContainer by iLevelOfView).OrderBy(group => group.Key);

            // On remet les index

            int iZIndex = 1;

            // Mise à jour sélection

            if(p_oOnTop != null)
                this.Selection = this.ItemContainerGenerator.ItemFromContainer((DependencyObject)p_oOnTop);

            // Groupe par groupe

            foreach (IGrouping<int, DependencyObject> oItemGroup in oItemsGroup)
            {
                // Elément par élément

                foreach (UIElement oItem in from oUIElement in oItemGroup.OfType<UIElement>()
                                            where oUIElement != oOnTopContainer // Pas le onTop
                                            let iUIElementZIndex = Panel.GetZIndex(oUIElement)
                                            let iRealZIndex = (iUIElementZIndex == 0) ? long.MaxValue : iUIElementZIndex
                                            orderby iRealZIndex ascending
                                            select oUIElement)
                {
                    Panel.SetZIndex(oItem, iZIndex++);
                }

                // Elément à mettre en avant

                if (oItemGroup.Key == iOnTopLevelOfView && oOnTopContainer != null)
                {
                    Panel.SetZIndex(oOnTopContainer, iZIndex++);
                }
            }
        }

        #endregion

        #region Fonctions protégées

        /// <summary>
        /// Nettoie le conteneur de l'élément spécifié.
        /// </summary>
        /// <param name="p_oElement">Conteneur à nettoyer.</param>
        /// <param name="p_oItem">Elément associé.</param>
        protected override void ClearContainerForItemOverride(DependencyObject p_oElement, object p_oItem)
        {
            base.ClearContainerForItemOverride(p_oElement, p_oItem);

            CanvasScatterViewItem oWrap = p_oElement as CanvasScatterViewItem;

            if (oWrap != null)
            {
                oWrap.AllOperationCompleted -= new OperationCompletedRoutedEventHandler(this.Item_AllOperationCompleted);
                oWrap.AllOperationDelta -= new OperationDeltaRoutedEventHandler(this.Item_AllOperationDelta);
                oWrap.AllOperationStarted -= new OperationStartedRoutedEventHandler(this.Item_AllOperationStarted);

                oWrap.FlingOutCompleted -= new RoutedEventHandler(this.Item_FlingOutCompleted);

                oWrap.InertiaCompleted -= new OperationCompletedRoutedEventHandler(this.Item_InertiaCompleted);
                oWrap.InertiaDelta -= new OperationDeltaRoutedEventHandler(this.Item_InertiaDelta);
                oWrap.InertiaStarted -= new OperationStartedRoutedEventHandler(this.Item_InertiaStarted);

                oWrap.ManipulationCompleted -= new OperationCompletedRoutedEventHandler(this.Item_ManipulationCompleted);
                oWrap.ManipulationDelta -= new OperationDeltaRoutedEventHandler(this.Item_ManipulationDelta);
                oWrap.ManipulationStarted -= new OperationStartedRoutedEventHandler(this.Item_ManipulationStarted);
            }

            // Mise à jour sélection

            if (this.Selection == p_oItem)
                this.Selection = null;
        }

        /// <summary>
        /// Obtient un nouveau conteneur pour les éléments.
        /// </summary>
        /// <returns>Nouvelle instance de <see cref="T:Black.SurfaceToolkit.Controls.CanvasScatterViewItem" />.</returns>
        protected override DependencyObject GetContainerForItemOverride()
        {
            return (new CanvasScatterViewItem(true));
        }

        /// <summary>
        /// Obtient une valeur indiquant si le contact d'identifiant spécifié est toujours en vie.
        /// </summary>
        /// <param name="p_iIdContact">Identifiant du contact dont on veut savoir s'il est toujours en vie.</param>
        /// <returns><see langword="true" /> si le contact d'identifiant <paramref name="p_iIdContact" /> en vie, <see langword="false" /> sinon.</returns>
        protected bool IsContactAlive(int p_iIdContact)
        {
            // Vérification existance scrutatteur

            if (this.m_oContactTarget == null)
                return (true);

            // Récupération des contacts

            Core.ReadOnlyContactCollection oContacts = this.m_oContactTarget.GetState();

            // Recherche du contact

            Core.Contact oSearch = oContacts.Where(i => i.Id == p_iIdContact).FirstOrDefault();

            // Test d'existance

            return (oSearch != null);
        }

        /// <summary>
        /// Obtient une valeur indiquant si l'élément spécifié est son propre conteneur.
        /// </summary>
        /// <param name="p_oItem">Objet à tester.</param>
        /// <returns><see langword="true" /> si <paramref name="p_oItem" /> est son propre conteneur, <see langword="false" /> sinon.</returns>
        protected override bool IsItemItsOwnContainerOverride(object p_oItem)
        {
            return (p_oItem is CanvasScatterViewItem);
        }

        /// <summary>
        /// Appelée lorsque l'élément séléctionné change.
        /// </summary>
        /// <param name="p_oOld">Ancienne valeur.</param>
        /// <param name="p_oNew">Nouvelle valeur.</param>
        protected virtual void OnSelectionChanged(object p_oOld, object p_oNew)
        {
            if (p_oOld != p_oNew)
                this.RaiseSelectionChangedEvent();
        }

        /// <summary>
        /// Prépare un conteneur pour recevoir un élément.
        /// </summary>
        /// <param name="p_oElement">Conteneur à préparer avec <paramref name="p_oItem" />.</param>
        /// <param name="p_oItem">Elément reçu par <paramref name="p_oElement" />.</param>
        protected override void PrepareContainerForItemOverride(DependencyObject p_oElement, object p_oItem)
        {
            // Appel au parent

            base.PrepareContainerForItemOverride(p_oElement, p_oItem);

            // Récupération de l'élément

            CanvasScatterViewItem oWrap = p_oElement as CanvasScatterViewItem;

            if (!this.IsItemItsOwnContainerOverride(p_oItem))
            {
                // Affectation des bindings sur la taille

                if (p_oItem is FrameworkElement)
                {
                    // On définit les dimensions de l'enfant au wrapper

                    oWrap.Width = ((FrameworkElement)p_oItem).ActualWidth;
                    oWrap.Height = ((FrameworkElement)p_oItem).ActualHeight;

                    // On automatise le redimensionnement

                    Binding oBindingWidth = new Binding()
                    {
                        Path = new PropertyPath(FrameworkElement.WidthProperty),
                        Source = p_oItem,
                        Mode = BindingMode.TwoWay
                    };

                    oWrap.SetBinding(FrameworkElement.WidthProperty, oBindingWidth);

                    Binding oBindingHeight = new Binding()
                    {
                        Path = new PropertyPath(FrameworkElement.HeightProperty),
                        Source = p_oItem,
                        Mode = BindingMode.TwoWay
                    };

                    oWrap.SetBinding(FrameworkElement.HeightProperty, oBindingHeight);
                }

                // On reporte la Dependency Property Attached Level Of View

                if (p_oItem is DependencyObject)
                {
                    CanvasScatterView.SetLevelOfView(oWrap, CanvasScatterView.GetLevelOfView((DependencyObject)p_oItem));

                    Binding oBindingLevelOfView = new Binding()
                    {
                        Path = new PropertyPath(CanvasScatterView.LevelOfViewProperty),
                        Source = p_oItem,
                        Mode = BindingMode.TwoWay
                    };

                    oWrap.SetBinding(CanvasScatterView.LevelOfViewProperty, oBindingLevelOfView);
                }
            }

            // On se branche sur les événements

            oWrap.AllOperationCompleted += new OperationCompletedRoutedEventHandler(this.Item_AllOperationCompleted);
            oWrap.AllOperationDelta += new OperationDeltaRoutedEventHandler(this.Item_AllOperationDelta);
            oWrap.AllOperationStarted += new OperationStartedRoutedEventHandler(this.Item_AllOperationStarted);

            oWrap.FlingOutCompleted += new RoutedEventHandler(this.Item_FlingOutCompleted);

            oWrap.InertiaCompleted += new OperationCompletedRoutedEventHandler(this.Item_InertiaCompleted);
            oWrap.InertiaDelta += new OperationDeltaRoutedEventHandler(this.Item_InertiaDelta);
            oWrap.InertiaStarted += new OperationStartedRoutedEventHandler(this.Item_InertiaStarted);

            oWrap.ManipulationCompleted += new OperationCompletedRoutedEventHandler(this.Item_ManipulationCompleted);
            oWrap.ManipulationDelta += new OperationDeltaRoutedEventHandler(this.Item_ManipulationDelta);
            oWrap.ManipulationStarted += new OperationStartedRoutedEventHandler(this.Item_ManipulationStarted);

            // On rafraichis la sélection

            this.Selection = p_oItem;
        }

        #endregion

        #region Fonctions privées
        
        /// <summary>
        /// Obtient la fenêtre associée.
        /// </summary>
        /// <returns>Fenêtre associée.</returns>
        private Window FindWindow()
        {
            DependencyObject oParent = this;

            // On boucle sur les parents

            do
            {
                // Récupération parent

                oParent = LogicalTreeHelper.GetParent(oParent);

                // On test si m_dC'est une window

                if (oParent is Window)
                    return ((Window)oParent);
            }
            while (oParent != null && !(oParent is Window));

            // Window non trouvé

            return (null);
        }

        /// <summary>
        /// Appelée lorsque l'événement <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.AllOperationCompleted" /> se produit sur un conteneur enfant.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void Item_AllOperationCompleted(object p_oSender, OperationCompletedRoutedEventArgs p_oArgs)
        {
            this.RaiseAllOperationCompletedEvent(p_oArgs);
        }

        /// <summary>
        /// Appelée lorsque l'événement <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.AllOperationDelta" /> se produit sur un conteneur enfant.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void Item_AllOperationDelta(object p_oSender, OperationDeltaRoutedEventArgs p_oArgs)
        {
            this.RaiseAllOperationDeltaEvent(p_oArgs);
        }

        /// <summary>
        /// Appelée lorsque l'événement <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.AllOperationStarted" /> se produit sur un conteneur enfant.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void Item_AllOperationStarted(object p_oSender, OperationStartedRoutedEventArgs p_oArgs)
        {
            this.RaiseAllOperationStartedEvent(p_oArgs);
        }

        /// <summary>
        /// Appelée lorsque l'événement <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.FlingOutCompleted" /> se produit sur un conteneur enfant.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void Item_FlingOutCompleted(object p_oSender, RoutedEventArgs p_oArgs)
        {
            this.RaiseCanvasFlingOutCompletedEvent();
        }

        /// <summary>
        /// Appelée lorsque l'événement <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.InertiaCompleted" /> se produit sur un conteneur enfant.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void Item_InertiaCompleted(object p_oSender, OperationCompletedRoutedEventArgs p_oArgs)
        {
            this.RaiseInertiaCompletedEvent(p_oArgs);
        }

        /// <summary>
        /// Appelée lorsque l'événement <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.InertiaDelta" /> se produit sur un conteneur enfant.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void Item_InertiaDelta(object p_oSender, OperationDeltaRoutedEventArgs p_oArgs)
        {
            this.RaiseInertiaDeltaEvent(p_oArgs);
        }

        /// <summary>
        /// Appelée lorsque l'événement <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.InertiaStarted" /> se produit sur un conteneur enfant.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void Item_InertiaStarted(object p_oSender, OperationStartedRoutedEventArgs p_oArgs)
        {
            this.RaiseInertiaStartedEvent(p_oArgs);
        }

        /// <summary>
        /// Appelée lorsque l'événement <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewDragItem.ItemDragEnded" /> se produit sur un conteneur enfant.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void Item_ItemDragEnded(object p_oSender, DragItemRoutedEventArgs p_oArgs)
        {
            this.RaiseCanvasDragEndedEvent(p_oArgs.Data, p_oArgs.Position, p_oArgs.ContactID);
        }

        /// <summary>
        /// Appelée lorsque l'événement <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.ManipulationCompleted" /> se produit sur un conteneur enfant.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void Item_ManipulationCompleted(object p_oSender, OperationCompletedRoutedEventArgs p_oArgs)
        {
            this.RaiseManipulationCompletedEvent(p_oArgs);
        }

        /// <summary>
        /// Appelée lorsque l'événement <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.ManipulationDelta" /> se produit sur un conteneur enfant.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void Item_ManipulationDelta(object p_oSender, OperationDeltaRoutedEventArgs p_oArgs)
        {
            this.RaiseManipulationDeltaEvent(p_oArgs);
        }

        /// <summary>
        /// Appelée lorsque l'événement <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.ManipulationStarted" /> se produit sur un conteneur enfant.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void Item_ManipulationStarted(object p_oSender, OperationStartedRoutedEventArgs p_oArgs)
        {
            this.RaiseManipulationStartedEvent(p_oArgs);
        }

        /// <summary>
        /// Déclenche l'événément <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.AllOperationCompleted" />.
        /// </summary>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void RaiseAllOperationCompletedEvent(OperationCompletedRoutedEventArgs p_oArgs)
        {
            p_oArgs.RoutedEvent = CanvasScatterView.AllOperationCompletedEvent;
            this.RaiseEvent(p_oArgs);
        }

        /// <summary>
        /// Déclenche l'événément <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.AllOperationDelta" />.
        /// </summary>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void RaiseAllOperationDeltaEvent(OperationDeltaRoutedEventArgs p_oArgs)
        {
            p_oArgs.RoutedEvent = CanvasScatterView.AllOperationDeltaEvent;
            this.RaiseEvent(p_oArgs);
        }

        /// <summary>
        /// Déclenche l'événément <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.AllOperationStarted" />.
        /// </summary>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void RaiseAllOperationStartedEvent(OperationStartedRoutedEventArgs p_oArgs)
        {
            p_oArgs.RoutedEvent = CanvasScatterView.AllOperationStartedEvent;
            this.RaiseEvent(p_oArgs);
        }

        /// <summary>
        /// Déclenche l'événément <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.CanvasDragEnded" />.
        /// </summary>
        /// <param name="p_oData">Information du dépôt.</param>
        /// <param name="p_oPosition">Position du dépôt.</param>
        /// <param name="p_iContactId">Identifiant du contact.</param>
        private void RaiseCanvasDragEndedEvent(object p_oData, Point p_oPosition, int p_iContactId)
        {
            this.RaiseEvent(new DragItemRoutedEventArgs(CanvasScatterView.CanvasDragEndedEvent, p_oData, p_oPosition, p_iContactId));
        }

        /// <summary>
        /// Déclenche l'événément <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.CanvasDragStarted" />.
        /// </summary>
        /// <param name="p_oData">Information du dépôt.</param>
        /// <param name="p_oPosition">Position du dépôt.</param>
        /// <param name="p_iContactId">Identifiant du contact.</param>
        private void RaiseCanvasDragStartedEvent(object p_oData, Point p_oPosition, int p_iContactId)
        {
            this.RaiseEvent(new DragItemRoutedEventArgs(CanvasScatterView.CanvasDragStartedEvent, p_oData, p_oPosition, p_iContactId));
        }

        /// <summary>
        /// Déclenche l'événément <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.CanvasFlingOutCompleted" />.
        /// </summary>
        private void RaiseCanvasFlingOutCompletedEvent()
        {
            this.RaiseEvent(new RoutedEventArgs(CanvasScatterView.CanvasFlingOutCompletedEvent, RoutedEventArgs.Empty));
        }

        /// <summary>
        /// Déclenche l'événément <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.InertiaCompleted" />.
        /// </summary>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void RaiseInertiaCompletedEvent(OperationCompletedRoutedEventArgs p_oArgs)
        {
            p_oArgs.RoutedEvent = CanvasScatterView.InertiaCompletedEvent;
            this.RaiseEvent(p_oArgs);
        }

        /// <summary>
        /// Déclenche l'événément <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.InertiaDelta" />.
        /// </summary>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void RaiseInertiaDeltaEvent(OperationDeltaRoutedEventArgs p_oArgs)
        {
            p_oArgs.RoutedEvent = CanvasScatterView.InertiaDeltaEvent;
            this.RaiseEvent(p_oArgs);
        }

        /// <summary>
        /// Déclenche l'événément <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.InertiaStarted" />.
        /// </summary>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void RaiseInertiaStartedEvent(OperationStartedRoutedEventArgs p_oArgs)
        {
            p_oArgs.RoutedEvent = CanvasScatterView.InertiaStartedEvent;
            this.RaiseEvent(p_oArgs);
        }

        /// <summary>
        /// Déclenche l'événément <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.ManipulationCompleted" />.
        /// </summary>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void RaiseManipulationCompletedEvent(OperationCompletedRoutedEventArgs p_oArgs)
        {
            p_oArgs.RoutedEvent = CanvasScatterView.ManipulationCompletedEvent;
            this.RaiseEvent(p_oArgs);
        }

        /// <summary>
        /// Déclenche l'événément <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.ManipulationDelta" />.
        /// </summary>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void RaiseManipulationDeltaEvent(OperationDeltaRoutedEventArgs p_oArgs)
        {
            p_oArgs.RoutedEvent = CanvasScatterView.ManipulationDeltaEvent;
            this.RaiseEvent(p_oArgs);
        }

        /// <summary>
        /// Déclenche l'événément <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.ManipulationStarted" />.
        /// </summary>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private void RaiseManipulationStartedEvent(OperationStartedRoutedEventArgs p_oArgs)
        {
            p_oArgs.RoutedEvent = CanvasScatterView.ManipulationStartedEvent;
            this.RaiseEvent(p_oArgs);
        }

        /// <summary>
        /// Déclenche l'événément <see cref="E:Black.SurfaceToolkit.Controls.CanvasScatterViewItem.SelectionChanged" />.
        /// </summary>
        private void RaiseSelectionChangedEvent()
        {
            this.RaiseEvent(new RoutedEventArgs(CanvasScatterView.SelectionChangedEvent, RoutedEventArgs.Empty));
        }

        #endregion

        #region Fonctions statiques publiques

        /// <summary>
        /// Obtient le niveau de calque de l'élément spécifié.
        /// </summary>
        /// <param name="p_oElement">Elément dont on veut le niveau de calque.</param>
        /// <returns>Niveau de calque de <paramref name="p_oElement" />.</returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="p_oElement" /> est <see langword="null" />.</exception>
        [AttachedPropertyBrowsableForType(typeof(CanvasScatterViewItem))]
        public static int GetLevelOfView(DependencyObject p_oElement)
        {
            if (p_oElement == null)
                throw new ArgumentNullException("p_oElement");

            return ((int)p_oElement.GetValue(CanvasScatterView.LevelOfViewProperty));
        }

        /// <summary>
        /// Définit le niveau de calque de l'élément spécifié.
        /// </summary>
        /// <param name="p_oElement">Elément dont on veut définir le niveau de calque.</param>
        /// <param name="p_iLevel">Niveau de calque de <paramref name="p_oElement" />.</param>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="p_oElement" /> est <see langword="null" />.</exception>
        [AttachedPropertyBrowsableForType(typeof(CanvasScatterViewItem))]
        public static void SetLevelOfView(DependencyObject p_oElement, int p_iLevel)
        {
            if (p_oElement == null)
                throw new ArgumentNullException("p_oElement");

            p_oElement.SetValue(CanvasScatterView.LevelOfViewProperty, p_iLevel);
        }

        #endregion

        #region Fonctions statiques privées

        /// <summary>
        /// Appelée lorsque la propriété <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.ItemsSource" /> est modifiée.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private static void OnItemsSourceChanged(DependencyObject p_oSender, DependencyPropertyChangedEventArgs p_oArgs)
        {
            ((CanvasScatterView)p_oSender).OnItemsSourceChanged((IEnumerable)p_oArgs.OldValue, (IEnumerable)p_oArgs.NewValue);
        }

        /// <summary>
        /// Appelée lorsque la propriété <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.LevelOfView" /> est modifiée.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private static void OnLevelOfViewChanged(DependencyObject p_oSender, DependencyPropertyChangedEventArgs p_oArgs)
        {
            CanvasScatterViewItem oScatterViewItem = p_oSender as CanvasScatterViewItem;

            if (oScatterViewItem == null)
                return;

            // On récupère le CanvasScatterView parent

            CanvasScatterView oScatterView = oScatterViewItem.Container;

            if (oScatterView != null)
                oScatterView.RefreshZIndexes(null);
        }

        /// <summary>
        /// Appelée lorsque la propriété <see cref="P:Black.SurfaceToolkit.Controls.CanvasScatterView.LevelOfView" /> est modifiée.
        /// </summary>
        /// <param name="p_oSender">Source de l'événement.</param>
        /// <param name="p_oArgs">Données de l'événement.</param>
        private static void OnSelectionChanged(DependencyObject p_oSender, DependencyPropertyChangedEventArgs p_oArgs)
        {
            ((CanvasScatterView)p_oSender).OnSelectionChanged((object)p_oArgs.OldValue, (object)p_oArgs.NewValue);
        }

        #endregion
    }
}
